<?php

namespace App\Admin\Service;

use App\Admin\Grid\NGrid;
use Encore\Admin\Form;
use Encore\Admin\Form\Field;
use Encore\Admin\Form\Field\Currency;
use Encore\Admin\Form\Field\Datetime;
use Encore\Admin\Form\Field\Number;
use Encore\Admin\Form\Field\Select;
use Encore\Admin\Grid\Column;
use Encore\Admin\Show;

class BaseService
{
    public string $table = 'demo';

    public array $l;

    public array $ml;

    public Form $form;

    public NGrid $grid;

    public Show $show;

    public int $id = 0;

    public function __construct()
    {
        $this->l = __('l');
        $this->ml = __($this->table);
    }

    /**
     * gid
     * @return void
     */
    public function gid(): void
    {
        $this->grid->column('id', 'ID')->sortable();
    }

    /**
     * gid
     * @return void
     */
    public function sid(): void
    {
        $this->show->field('id', 'ID');
    }

    /**
     * show
     * @param int $id
     * @return void
     */
    public function show(int $id): void
    {
        $this->id = $id;
    }

    /**
     * column
     * @param string $column
     * @return bool|Column|null
     */
    public function column(string $column): bool|Column|null
    {
        if (str_contains($column, ',')) {
            $column = explode(',', $column);
            foreach ($column as $v) {
                $label = $this->ml[lineToHump($v)] ?? null;
                if (is_null($label)) $label = $this->l[lineToHump($v)] ?? null;
                $this->grid->column(humpToLine($v), $label);
            }
            return null;
        } else {
            $label = $this->ml[lineToHump($column)] ?? null;
            if (is_null($label)) $label = $this->l[lineToHump($column)] ?? null;
            return $this->grid->column(humpToLine($column), $label);
        }
    }

    /**
     * using
     * @param string $column
     * @param array|null $using
     * @return void
     */
    public function using(string $column, ?array $using = null): void
    {
        $columnArr = explode(',', $column);
        foreach ($columnArr as $column) {
            $label = $this->ml[lineToHump($column)] ?? null;
            if (is_null($label)) $label = $this->l[lineToHump($column)];
            if (is_null($using)) {
                $using = $this->ml[lineToHump($column) . 'Arr'] ?? null;
                if (is_null($using)) $using = $this->l[lineToHump($column) . 'Arr'];
            }
            if ($this->id === 0) {
                $this->grid->column(humpToLine($column), $label)->using($using);
            } else {
                $this->show->field(humpToLine($column), $label)->using($using);
            }
        }
    }

    /**
     * using
     * @param string $column
     * @return void
     */
    public function fileId(string $column = 'fileId'): void
    {
        $label = $this->ml['fileId'] ?? $this->l['fileId'];
        if ($this->id === 0) {
            $this->grid->column(humpToLine($column), $label)->display(function ($field) {
                if (empty($field)) return null;
                else return fileIdToUrl($field);
            })->image(config('oss.url'), 60, 60);
        } else {
            $this->show->field(humpToLine($column), $label)->unescape()->as(function ($field) {
                if (empty($field)) return null;
                else return fileIdToUrl($field);
            })->image(config('oss.url'), 100, 100);
        }
    }

    /**
     * field
     * @param string|array $field
     * @return Show\Field|null
     */
    public function field(string|array $field): ?Show\Field
    {
        if (is_string($field) && !str_contains($field, ',')) {
            $label = $this->ml[lineToHump($field)] ?? null;
            if (is_null($label)) $label = $this->l[lineToHump($field)];
            return $this->show->field(humpToLine($field), $label);
        } else {
            if (is_string($field)) $field = explode(',', $field);
            foreach ($field as $v) {
                $label = $this->ml[lineToHump($v)] ?? null;
                if (is_null($label)) $label = $this->l[lineToHump($v)];
                $this->show->field(humpToLine($v), $label);
            }
            return null;
        }
    }

    /**
     * hidden
     * @param string $string
     * @return void
     */
    public function hidden(string $string): void
    {
        $string = explode(',', $string);
        foreach ($string as $v) {
            $vv = explode('~', $v);
            if (count($vv) === 1) $this->form->hidden(humpToLine($v));
            else $this->form->hidden(humpToLine($vv[0]))->default($vv[1]);
        }
    }

    /**
     * text
     * @param string $string
     * @return void
     */
    public function text(string $string): void
    {
        $string = explode(',', $string);
        foreach ($string as $v) {
            $vv = explode('~', $v);
            if (count($vv) === 1) {
                $label = $this->ml[lineToHump($v)] ?? null;
                $this->form->text(humpToLine($v), $label ?? $this->l[lineToHump($v)]);
            } else {
                $label = $this->ml[lineToHump($vv[0])] ?? null;
                $text = $this->form->text(humpToLine($vv[0]), $label ?? $this->l[lineToHump($vv[0])]);
                if (str_contains($vv[1], 'required')) {
                    $text->required();
                    $vv[1] = str_replace('required:', '', $vv[1]);
                }
                if (str_contains($vv[1], 'attribute')) {
                    foreach (explode('^', str_replace('attribute:', '', $vv[1])) as $attr) {
                        $attrArr = explode('|', $attr);
                        $text->attribute($attrArr[0], $attrArr[1]);
                    }
                }
            }
        }
    }

    /**
     * select
     * @param string $string
     * @param array|null $options
     * @param int $required
     * @param string|null $load
     * @return Select
     */
    public function select(string $string, array $options = null, int $required = 0, string $load = null): Select
    {
        $label = $this->ml[lineToHump($string)] ?? null;
        $select = $this->form->select(humpToLine($string), $label ?? $this->l[lineToHump($string)]);
        if (is_null($options)) {
            $using = $this->ml[lineToHump($string) . 'Arr'] ?? null;
            if (is_null($using)) $options = $this->l[lineToHump($string) . 'Arr'];
        }
        $select->options($options ?? []);
        if ($required === 1) $select->required();
        if (!is_null($load)) {
            $arr = explode(',', $load);
            if (count($arr) === 1) $select->default($load);
            else $select->load(humpToLine($arr[0]), $arr[1]);
        }
        return $select;
    }

    /**
     * currency
     * @param string $s
     * @param int $l
     * @return Currency
     */
    public function currency(string $s, int $l = 5): Currency
    {
        $label = $this->ml[lineToHump($s)] ?? null;
        return $this->form->currency(humpToLine($s), $label ?? $this->l[lineToHump($s)])->symbol('￥')->default(0)
            ->attribute('maxlength', $l)->required();
    }

    /**
     * datetime
     * @param string $s
     * @return Datetime
     */
    public function datetime(string $s): Datetime
    {
        $label = $this->l[lineToHump($s)] ?? null;
        return $this->form->datetime(humpToLine($s), $label ?? $this->ml[lineToHump($s)])
            ->default(now()->startOfDay()->toDateTimeString())->required();
    }

    /**
     * number
     * @param string $s
     * @param int $l
     * @return Number
     */
    public function number(string $s, int $l = 5): Number
    {
        $label = $this->l[lineToHump($s)] ?? null;
        return $this->form->number(humpToLine($s), $label ?? $this->ml[lineToHump($s)])
            ->default(0)->min(0)->attribute('maxlength', $l)->required();
    }

    /**
     * number
     * @param string|array $s
     * @return void
     */
    public function image(string $column): void
    {
        foreach (explode(',', $column) as $v) {
            $label = $this->ml[lineToHump($v)] ?? null;
            $this->grid->column(humpToLine($v), $label ?? $this->l[lineToHump($v)])->display(function ($column) use ($v) {
                if (!is_null($column)) return view('image', ['id' => $this->id . $v, 'image' => fileIdToUrl($column)]);
                else return null;
            });
        }
    }
}
